Pythonμ μ¬μ©νμ¬ μμ ν μνΈνν μ§κ°μ μ²μλΆν° ꡬμΆνλ λ°©λ²μ λ°°μλλ€. μ΄ μ¬μΈ΅ κ°μ΄λλ μ£Όμ κ°λ , μνΈν, λΌμ΄λΈλ¬λ¦¬ λ° μ€μ©μ μΈ μ½λ μμ λ₯Ό λ€λ£Ήλλ€.
PythonμΌλ‘ μνΈνν μ§κ° ꡬμΆνκΈ°: μ’ ν© κ°μ΄λ
κΈλ³νλ λμ§νΈ κΈμ΅ μΈκ³μμ μνΈννλ λ³νμ μΈ νμΌλ‘ λΆμνμ΅λλ€. μ΄ νλͺ μ ν΅μ¬μλ λΈλ‘μ²΄μΈ λ€νΈμν¬μ μνΈ μμ©νλ κ°μΈ κ²μ΄νΈμ¨μ΄μΈ μ§κ° κ°λ μ΄ μμ΅λλ€. μμ€μ λ§μ μμ μ© μ§κ°μ΄ μ‘΄μ¬νμ§λ§, κ·Έ λ΄λΆ μλ λ°©μμ μ΄ν΄νλ κ²μ λͺ¨λ κ°λ°μλ κΈ°μ μ νΈκ°μκ² κ·μ€ν κΈ°μ μ λλ€. μ΄ κ°μ΄λλ Pythonμ μ¬μ©νμ¬ κΈ°λ₯μ μΈ μνΈνν μ§κ°μ μ²μλΆν° λ§λλ κ³Όμ μ μλ΄ν¨μΌλ‘μ¨ μ΄ κ³Όμ μ λͺ νν ν κ²μ λλ€.
μ°λ¦¬λ κΈ°λ³Έ μνΈν μ리, νμ Python λΌμ΄λΈλ¬λ¦¬, κ·Έλ¦¬κ³ ν€ μμ±, λΉνΈμ½μΈ λ° μ΄λ리μ μ£Όμ μμ±, νΈλμμ μλͺ μ μν λ¨κ³λ³ ꡬνμ λ€λ£° κ²μ λλ€. μ΄ κΈμ λ§μΉ λμ―€μ΄λ©΄ μ§κ° λ©μ»€λμ¦μ λν νκ³ ν μ΄ν΄μ μλνλ μμ λ§μ λͺ λ Ήμ€ μ§κ°μ κ°κ² λ κ²μ λλ€.
λ©΄μ± μ‘°ν: μ΄ κ°μ΄λμ μ μλ μ½λμ κ°λ μ κ΅μ‘ λͺ©μ μΌλ‘λ§ μ¬μ©λ©λλ€. νλ‘λμ μμ€μ μ§κ°μ ꡬμΆνλ €λ©΄ μ격ν 보μ κ°μ¬, κ΄λ²μν ν μ€νΈ λ° κ³ κΈ λ³΄μ μ‘°μΉκ° νμν©λλ€. μ¬κΈ°μ μμ±λ μ§κ°μ μ€μ μκΈ μ μ₯μ μ¬μ©νμ§ λ§μμμ€.
μνΈνν μ§κ°μ ν΅μ¬ κ°λ μ΄ν΄
μ½λλ₯Ό ν μ€λ μμ±νκΈ° μ μ μνΈνν μ§κ°μ΄ μ§μ μΌλ‘ 무μμΈμ§ νμ νλ κ²μ΄ μ€μν©λλ€. μ΄λ¦κ³Όλ λ¬λ¦¬ μ§κ°μ μ½μΈμ "μ μ₯"νμ§ μμ΅λλ€. μνΈννλ λΆμ° μμ₯μΈ λΈλ‘체μΈμ κΈ°λ‘μΌλ‘ μ‘΄μ¬ν©λλ€. μ§κ°μ ν΄λΉ μμ₯μ μλ μμ°μ λν μμ κΆκ³Ό μ μ΄κΆμ λΆμ¬νλ μνΈν ν€λ₯Ό κ΄λ¦¬νλ μννΈμ¨μ΄μ λλ€.
λͺ¨λ λΉμνν μ§κ°μ μ£Όμ κ΅¬μ± μμλ λ€μκ³Ό κ°μ΅λλ€:
1. κ°μΈ ν€: λΉμ μ λμ§νΈ λΉλ°
κ°μΈ ν€λ μ§κ°μμ κ°μ₯ μ€μν μ 보μ λλ€. λ§€μ° ν¬κ³ 무μμλ‘ μμ±λ μ«μμ΄λ©°, λΉλ°λ‘ μ μ§λκ³ λΉμ λ§μ΄ μκ³ μμ΅λλ€. κ·Έ λͺ©μ μ λμ§νΈ μλͺ μ μμ±νλ κ²μΌλ‘, μ΄λ λΉμ μ΄ νΈλμμ μ μΉμΈνμμ λ°λ°ν μ μλ μ¦κ±°λ‘ μμ©ν©λλ€. κ°μΈ ν€λ₯Ό μμ΄λ²λ¦¬λ©΄ μκΈμ λν μ κ·Ό κΆνμ μμν μκ² λ©λλ€. λ€λ₯Έ μ¬λμ΄ μ κ·Ό κΆνμ μ»μΌλ©΄ κ·Έλ€μ λΉμ μ μκΈμ μμ ν ν΅μ νκ² λ©λλ€.
- λΉμ : κ°μΈ ν€λ₯Ό λμ§νΈ κΈκ³ μ λ§μ€ν° ν€λΌκ³ μκ°νμΈμ. κΈκ³ λ₯Ό μ΄κ³ λ΄μ©λ¬Όμ μ΄λμ μΉμΈν μ μμ΅λλ€.
2. κ³΅κ° ν€: λΉμ μ 곡μ κ°λ₯ν μλ³μ
κ³΅κ° ν€λ νμ 곑μ μνΈν (ECC)λ‘ μλ €μ§ λ¨λ°©ν₯ μνΈν ν¨μλ₯Ό μ¬μ©νμ¬ κ°μΈ ν€μμ μνμ μΌλ‘ νμλ©λλ€. κ°μΈ ν€λ‘λΆν° κ³΅κ° ν€λ₯Ό μμ±νλ κ²μ κ°λ₯νμ§λ§, κ·Έ λ°λλ₯Ό μννλ κ²μ κ³μ°μ μΌλ‘ λΆκ°λ₯ν©λλ€. μ΄ λ¨λ°©ν₯ κ΄κ³λ μνΈνν 보μμ κΈ°λ°μ λλ€.
- λΉμ : κ³΅κ° ν€λ λΉμ μ μν κ³μ’ λ²νΈμ κ°μ΅λλ€. λ€λ₯Έ μ¬λλ€κ³Ό 곡μ νμ¬ λμ λ°μ μ μμ§λ§, μ΄λ κ·Έλ€μκ² μκΈμ μΈμΆν κΆνμ μ£Όμ§λ μμ΅λλ€.
3. μ£Όμ: λΉμ μ κ³΅κ° λͺ©μ μ§
μ§κ° μ£Όμλ κ³΅κ° ν€λ₯Ό λ μ§§κ³ μ¬μ©μ μΉνμ μΌλ‘ ννν κ²μ λλ€. κ³΅κ° ν€μ μΆκ° ν΄μ± μκ³ λ¦¬μ¦ (μ: SHA-256 λ° RIPEMD-160)μ μ μ©νμ¬ μμ±λλ©°, μκΈμ λ³΄λΌ λ μ€νλ₯Ό λ°©μ§νκΈ° μν 체ν¬μ¬μ΄ μ’ μ’ ν¬ν¨λ©λλ€. μ΄κ²μ μνΈννλ₯Ό λ°κΈ° μν΄ λ€λ₯Έ μ¬λλ€κ³Ό 곡μ νλ λ¬Έμμ΄μ λλ€.
- λΉμ : κ³΅κ° ν€κ° κ³μ’ λ²νΈλΌλ©΄, μ£Όμλ μ€λ₯ κ²μ¬ κΈ°λ₯μ΄ ν¬ν¨λ νΉμ νμμ μ²κ΅¬μ λ²νΈμ κ°μ΅λλ€.
4. μνΈν λ§ν¬: λ¨λ°©ν₯ ν΅λ‘
μ΄λ¬ν κ΅¬μ± μμ κ°μ κ΄κ³λ μ격ν λ¨λ°©ν₯ κ³μΈ΅ ꡬ쑰μ λλ€:
κ°μΈ ν€ β κ³΅κ° ν€ β μ£Όμ
μ΄ λμμΈμ λΉμ μ΄ κ³΅κ° ν€λ₯Ό μ§μ λ ΈμΆνμ§ μκ³ (μ΄λ€ κ²½μ°μλ) κ·Έλ¦¬κ³ νμ€ν κ°μΈ ν€λ₯Ό μ λ λ ΈμΆνμ§ μκ³ λ μ£Όμλ₯Ό μμ νκ² κ³΅μ ν μ μλλ‘ λ³΄μ₯ν©λλ€.
5. λμ§νΈ μλͺ : μμ κΆ μ¦λͺ
μνΈννλ₯Ό 보λ΄λ €λ©΄ νΈλμμ λ©μμ§ (μ: "μ£Όμ Aμμ μ£Όμ Bλ‘ 0.5 BTC μ μ‘")λ₯Ό μμ±ν©λλ€. κ·Έλ° λ€μ μ§κ° μννΈμ¨μ΄λ κ°μΈ ν€λ₯Ό μ¬μ©νμ¬ ν΄λΉ νΉμ νΈλμμ μ λν κ³ μ ν λμ§νΈ μλͺ μ μμ±ν©λλ€. μ΄ μλͺ μ νΈλμμ κ³Ό ν¨κ» λ€νΈμν¬μ λΈλ‘λμΊμ€νΈλ©λλ€. λ€νΈμν¬μ μ±κ΅΄μμ λ Έλλ λΉμ μ κ³΅κ° ν€λ₯Ό μ¬μ©νμ¬ μλͺ μ΄ μ ν¨νμ§ νμΈν μ μμΌλ©°, λΉμ μ κ°μΈ ν€λ₯Ό λ³΄μ§ μκ³ λ μκΈμ ν©λ²μ μΈ μμ μκ° νΈλμμ μ μΉμΈνμμ νμΈν©λλ€.
Python κ°λ° νκ²½ μ€μ
μ§κ°μ ꡬμΆνλ €λ©΄ 볡μ‘ν μνΈνλ₯Ό μ²λ¦¬νλ λͺ κ°μ§ νΉμ Python λΌμ΄λΈλ¬λ¦¬κ° νμν©λλ€. Python 3.6 μ΄μμ΄ μ€μΉλμ΄ μλμ§ νμΈνμΈμ. pipλ₯Ό μ¬μ©νμ¬ νμν ν¨ν€μ§λ₯Ό μ€μΉν μ μμ΅λλ€:
pip install ecdsa pysha3 base58
κ° λΌμ΄λΈλ¬λ¦¬κ° μννλ μμ μ μ΄ν΄λ³΄κ² μ΅λλ€:
- ecdsa: μ΄κ²μ νμ 곑μ λμ§νΈ μλͺ
μκ³ λ¦¬μ¦ (ECDSA) ꡬνμ μν μ€μν λΌμ΄λΈλ¬λ¦¬μ
λλ€. μ°λ¦¬λ λΉνΈμ½μΈ, μ΄λ리μ λ° κΈ°ν λ§μ μνΈννμμ μ¬μ©λλ νμ€μΈ
SECP256k1곑μ μ κΈ°λ°μΌλ‘ κ°μΈ ν€μ κ³΅κ° ν€λ₯Ό μμ±νλ λ° μ¬μ©ν κ²μ λλ€. λν λμ§νΈ μλͺ μ μμ± λ° κ²μ¦λ μ²λ¦¬ν©λλ€. - pysha3: Pythonμ λ΄μ₯
hashlibμ λ§μ ν΄μ± μκ³ λ¦¬μ¦μ μ§μνμ§λ§, μ΄λ리μ μ£Όμ μμ±μ νμν Keccak-256μ ν¬ν¨νμ§ μμ΅λλ€. μ΄ λΌμ΄λΈλ¬λ¦¬λ ν΄λΉ κΈ°λ₯μ μ 곡ν©λλ€. - base58: μ΄ λΌμ΄λΈλ¬λ¦¬λ μ¬λμ΄ μ½μ μ μλ λΉνΈμ½μΈ μ£Όμλ₯Ό μμ±νλ λ° μ¬μ©λλ νμμΈ Base58Check μΈμ½λ©μ ꡬνν©λλ€. μ€νλ‘ μΈν μ€λ₯λ₯Ό λ°©μ§νλ λ° λμμ΄ λλ 체ν¬μ¬μ ν¬ν¨ν©λλ€.
- hashlib: μ΄ λ΄μ₯ Python λΌμ΄λΈλ¬λ¦¬λ λΉνΈμ½μΈ μ£Όμλ₯Ό μμ±νλ νμ λ¨κ³μΈ SHA-256 λ° RIPEMD-160 ν΄μ±μ μ¬μ©λ κ²μ λλ€.
λ¨κ³λ³ ꡬν: μ§κ° λ‘μ§ κ΅¬μΆ
μ΄μ μ½λλ‘ λ€μ΄κ° λ΄ μλ€. μ°λ¦¬λ μ§κ°μ ν΅μ¬ κΈ°λ₯μ λ¨κ³λ³λ‘ ꡬμΆνκ³ κ° λ¨κ³λ₯Ό μ€λͺ ν κ²μ λλ€.
Step 1: κ°μΈ ν€ μμ±
κ°μΈ ν€λ λ³Έμ§μ μΌλ‘ 256λΉνΈ (32λ°μ΄νΈ) μ«μμ λλ€. κ°μ₯ μ€μν μꡬ μ¬νμ μ§μ ν 무μμμ±μΌλ‘ μμ±λμ΄μΌ νλ€λ κ²μ λλ€. μ½ν λμ μμ±κΈ°λ₯Ό μ¬μ©νλ©΄ 곡격μκ° μΆμΈ‘ν μ μλ μμΈ‘ κ°λ₯ν ν€κ° μμ±λ μ μμ΅λλ€.
Pythonμ λ΄μ₯ secrets λͺ¨λμ μνΈνμ μΌλ‘ μμ ν λμλ₯Ό μμ±νλλ‘ μ€κ³λμ΄ μ°λ¦¬μκ² μλ²½ν©λλ€.
μ¬κΈ°μ os.urandom(32)λ 32λ°μ΄νΈμ μνΈνμ μΌλ‘ μμ ν λμλ₯Ό μ 곡νλ©°, μ΄λ 256λΉνΈ κ°μΈ ν€μ μ νν νμν κ²μ
λλ€.
Step 2: κ³΅κ° ν€ νμ
λ€μμΌλ‘, μ°λ¦¬λ SECP256k1 νμ 곑μ μ μ¬μ©νμ¬ κ°μΈ ν€λ‘λΆν° κ³΅κ° ν€λ₯Ό νμν©λλ€. ecdsa λΌμ΄λΈλ¬λ¦¬λ μ΄ κ³Όμ μ κ°λ¨νκ² λ§λλλ€.
ecdsa.SigningKey κ°μ²΄λ μ°λ¦¬μ κ°μΈ ν€λ₯Ό λνλ
λλ€. κ·Έλ° λ€μ ν΄λΉ verifying_key (κ³΅κ° ν€)λ₯Ό κ°μ Έμ "λΉμμΆ" νμμΌλ‘ λ΄λ³΄λ
λλ€. λΉμμΆ κ³΅κ° ν€λ 65λ°μ΄νΈ κΈΈμ΄μ
λλ€: 0x04 μ λμ¬μ νμ 곑μ μμ μ μ 32λ°μ΄νΈ X μ’ν λ° 32λ°μ΄νΈ Y μ’νκ° λ€λ°λ¦
λλ€.
Step 3: λΉνΈμ½μΈ μ£Όμ μμ±
κ³΅κ° ν€μμ λΉνΈμ½μΈ μ£Όμλ₯Ό μμ±νλ κ²μ 보μ λ° μ€λ₯ κ²μ¬λ₯Ό μν΄ μ€κ³λ λ€λ¨κ³ νλ‘μΈμ€μ λλ€. λ€μμ νμ€ P2PKH (Pay-to-Public-Key-Hash) μ£Όμ μμ± νλ¦μ λλ€:
- SHA-256 ν΄μ±: SHA-256μ μ¬μ©νμ¬ κ³΅κ° ν€λ₯Ό ν΄μ±ν©λλ€.
- RIPEMD-160 ν΄μ±: μ΄μ λ¨κ³μ κ²°κ³Όλ₯Ό RIPEMD-160μ μ¬μ©νμ¬ ν΄μ±ν©λλ€.
- λ²μ λ°μ΄νΈ μΆκ°: RIPEMD-160 ν΄μμ λ²μ λ°μ΄νΈ μ λμ¬λ₯Ό μΆκ°ν©λλ€. λΉνΈμ½μΈ λ©μΈλ·μ κ²½μ°
0x00μ λλ€. - 체ν¬μ¬ κ³μ°: νμ₯λ ν΄μμ λν΄ SHA-256 ν΄μ±μ λ λ² μννκ³ , μ΅μ’ ν΄μμ μ²μ 4λ°μ΄νΈλ₯Ό μ·¨ν©λλ€. μ΄κ²μ΄ 체ν¬μ¬μ λλ€.
- 체ν¬μ¬ μΆκ°: λ²μ μ λμ¬κ° λΆμ ν΄μμ λμ 4λ°μ΄νΈ 체ν¬μ¬μ μΆκ°ν©λλ€.
- Base58Check μΈμ½λ©: Base58Checkλ₯Ό μ¬μ©νμ¬ μ 체 λ°μ΄νΈ λ¬Έμμ΄μ μΈμ½λ©νμ¬ μ΅μ’ μ μΌλ‘ μ¬λμ΄ μ½μ μ μλ μ£Όμλ₯Ό μ»μ΅λλ€.
Pythonμμ μ΄λ₯Ό ꡬνν΄ λ΄ μλ€:
```python def public_key_to_btc_address(public_key_bytes): """Convert a public key to a Bitcoin P2PKH address.""" # Step 1 & 2: SHA-256 then RIPEMD-160 sha256_hash = hashlib.sha256(public_key_bytes).digest() ripemd160_hash = hashlib.new('ripemd160') ripemd160_hash.update(sha256_hash) hashed_public_key = ripemd160_hash.digest() # Step 3: Add version byte (0x00 for Mainnet) version_byte = b'\x00' versioned_hash = version_byte + hashed_public_key # Step 4 & 5: Create checksum and append # Double SHA-256 hash checksum_hash_1 = hashlib.sha256(versioned_hash).digest() checksum_hash_2 = hashlib.sha256(checksum_hash_1).digest() checksum = checksum_hash_2[:4] binary_address = versioned_hash + checksum # Step 6: Base58Check encode btc_address = base58.b58encode(binary_address).decode('utf-8') return btc_address ```Step 4: μ΄λ리μ μ£Όμ μμ±
μ΄λ리μ μ£Όμ μμ±μ λΉνΈμ½μΈμ λΉν΄ λ κ°λ¨ν©λλ€. κ³΅κ° ν€μ Keccak-256 ν΄μλ₯Ό μ·¨νκ³ κ²°κ³Όμ λ§μ§λ§ 20λ°μ΄νΈλ₯Ό μ¬μ©νλ κ²μ ν¬ν¨ν©λλ€.
- Keccak-256 ν΄μ±: κ³΅κ° ν€μ Keccak-256 ν΄μλ₯Ό μ·¨ν©λλ€.
0x04μ λμ¬κ° μλ κ³΅κ° ν€λ₯Ό μ¬μ©ν΄μΌ ν©λλ€. - λ§μ§λ§ 20λ°μ΄νΈ μ·¨νκΈ°: μ΄λ리μ μ£Όμλ μ΄ ν΄μμ λ§μ§λ§ 20λ°μ΄νΈ (40κ°μ 16μ§μ λ¬Έμ)μ λλ€.
- νμ: μ£Όμμ `0x` μ λμ¬λ₯Ό λΆμ΄λ κ²μ΄ νμ€μ λλ€.
pysha3λ₯Ό μ¬μ©νμ¬ μ΄λ₯Ό ꡬνν΄ λ΄
μλ€:
Step 5: λ©μμ§ μλͺ
λμ§νΈ μλͺ μ κ°μΈ ν€ μμ μκ° λ©μμ§ (μ: νΈλμμ )λ₯Ό μΉμΈνμμ μ¦λͺ ν©λλ€. μ΄ κ³Όμ μ ν¨μ¨μ±κ³Ό 보μμ μν΄ μμ λ©μμ§ μμ²΄κ° μλ λ©μμ§μ ν΄μλ₯Ό μλͺ νλ κ²μ ν¬ν¨ν©λλ€.
```python def sign_message(private_key_bytes, message): """Sign a message with the given private key.""" # It's standard practice to sign the hash of the message message_hash = hashlib.sha256(message.encode('utf-8')).digest() sk = ecdsa.SigningKey.from_string(private_key_bytes, curve=ecdsa.SECP256k1) signature = sk.sign(message_hash) return signature ```Step 6: μλͺ νμΈ
νμΈμ μ κ³Όμ μ λλ€. κ³΅κ° ν€, μλ³Έ λ©μμ§ λ° μλͺ μ κ°μ§ λꡬλ μ§ μλͺ μ΄ μ§μ§μμ νμΈν μ μμ΅λλ€. μ΄κ²μ΄ λΈλ‘μ²΄μΈ λ€νΈμν¬κ° νΈλμμ μ κ²μ¦νλ λ°©λ²μ λλ€.
```python def verify_signature(public_key_bytes, signature, message): """Verify a signature for a message with the given public key.""" message_hash = hashlib.sha256(message.encode('utf-8')).digest() vk = ecdsa.VerifyingKey.from_string(public_key_bytes, curve=ecdsa.SECP256k1, hashfunc=hashlib.sha256) try: # The verify method will return True if valid, or raise an exception return vk.verify(signature, message_hash) except ecdsa.BadSignatureError: return False ```μ§κ° 쑰립: κ°λ¨ν λͺ λ Ήμ€ μΈν°νμ΄μ€ (CLI)
μ΄μ λͺ¨λ ν΅μ¬ κΈ°λ₯μ κ°μΆμμΌλ, μ΄λ₯Ό κ°λ¨νκ³ μ μ©ν λͺ
λ Ήμ€ λκ΅¬λ‘ λ§λ€μ΄ λ΄
μλ€. λ‘μ§μ μΊ‘μννκΈ° μν΄ Wallet ν΄λμ€λ₯Ό μμ±νκ³ , Pythonμ argparse λͺ¨λμ μ¬μ©νμ¬ μ¬μ©μ λͺ
λ Ήμ μ²λ¦¬ν κ²μ
λλ€.
λ€μμ λͺ¨λ κΈ°λ₯μ μμ§λ ₯ μλ μ ν리μΌμ΄μ μΌλ‘ ν΅ν©νλ μμ ν μ€ν¬λ¦½νΈμ λλ€.
```python #!/usr/bin/env python3 import os import hashlib import base58 import ecdsa import argparse from sha3 import keccak_256 class Wallet: """Represents a cryptocurrency wallet with key management and address generation.""" def __init__(self, private_key_hex=None): if private_key_hex: self.private_key = bytes.fromhex(private_key_hex) else: self.private_key = self._generate_private_key() self.public_key = self._private_to_public_key(self.private_key) self.btc_address = self._public_to_btc_address(self.public_key) self.eth_address = self._public_to_eth_address(self.public_key) def _generate_private_key(self): return os.urandom(32) def _private_to_public_key(self, private_key): sk = ecdsa.SigningKey.from_string(private_key, curve=ecdsa.SECP256k1) return sk.verifying_key.to_string("uncompressed") def _public_to_btc_address(self, public_key): sha256_hash = hashlib.sha256(public_key).digest() ripemd160 = hashlib.new('ripemd160') ripemd160.update(sha256_hash) hashed_pk = ripemd160.digest() versioned_hash = b'\x00' + hashed_pk checksum = hashlib.sha256(hashlib.sha256(versioned_hash).digest()).digest()[:4] binary_address = versioned_hash + checksum return base58.b58encode(binary_address).decode('utf-8') def _public_to_eth_address(self, public_key): uncompressed_pk = public_key[1:] keccak_hash = keccak_256(uncompressed_pk).digest() return '0x' + keccak_hash[-20:].hex() def display_details(self): print(f"Private Key (hex): {self.private_key.hex()}") print(f"Public Key (hex): {self.public_key.hex()}") print(f"Bitcoin Address: {self.btc_address}") print(f"Ethereum Address: {self.eth_address}") def main(): parser = argparse.ArgumentParser(description="A simple command-line cryptocurrency wallet.") parser.add_argument("command", choices=["create", "details"], help="The command to execute.") parser.add_argument("--privatekey", help="An existing private key in hex format to get details from.") args = parser.parse_args() if args.command == "create": wallet = Wallet() print("--- New Wallet Created ---") wallet.display_details() print("\n*** IMPORTANT ***") print("Save your private key in a secure location. It is the only way to access your funds.") elif args.command == "details": if not args.privatekey: print("Error: The 'details' command requires a private key using the --privatekey flag.") return try: wallet = Wallet(private_key_hex=args.privatekey) print("--- Wallet Details ---") wallet.display_details() except Exception as e: print(f"Error loading wallet from private key: {e}") if __name__ == "__main__": main() ```μ΄ CLI λꡬ μ¬μ©λ²:
- μ μ½λλ₯Ό Python νμΌλ‘ μ μ₯ν©λλ€ (μ:
cli_wallet.py). - ν°λ―Έλ λλ λͺ λ Ή ν둬ννΈλ₯Ό μ½λλ€.
- μ μ§κ° μμ±:
python cli_wallet.py create - κΈ°μ‘΄ κ°μΈ ν€μμ μΈλΆ μ 보 보기:
python cli_wallet.py details --privatekey YOUR_PRIVATE_KEY_IN_HEX
보μ λͺ¨λ² μ¬λ‘ λ° μ€μ κ³ λ € μ¬ν
κΈ°λ³Έ μ§κ°μ μ±κ³΅μ μΌλ‘ ꡬμΆνμ§λ§, νλ‘λμ μ€λΉκ° λ μ ν리μΌμ΄μ μ 보μμ ν¨μ¬ λ κΉμ΄ μ§μ€ν΄μΌ ν©λλ€. λ€μμ κ³ λ €ν΄μΌ ν λͺ κ°μ§ μ€μν μ¬νμ λλ€.
1. κ°μΈ ν€λ₯Ό μΌλ° ν μ€νΈλ‘ μ λ μ μ₯νμ§ λ§μμμ€
μ°λ¦¬ μ€ν¬λ¦½νΈλ κ°μΈ ν€λ₯Ό μ½μμ μΆλ ₯νλλ°, μ΄λ λ§€μ° μμ νμ§ μμ΅λλ€. μ€μ μ ν리μΌμ΄μ μμλ κ°μΈ ν€λ₯Ό κ°λ ₯ν λΉλ°λ²νΈλ₯Ό μ¬μ©νμ¬ μ μ₯ μ μνΈνν΄μΌ ν©λλ€. μλͺ μ νμν λλ§ λ©λͺ¨λ¦¬μμ μνΈ ν΄λ λμ΄μΌ ν©λλ€. μ λ¬Έμ μΈ μ루μ μ μ’ μ’ νλμ¨μ΄ 보μ λͺ¨λ (HSM) λλ μ₯μΉμ 보μ μΈν΄λ μ΄λΈλ₯Ό μ¬μ©νμ¬ ν€λ₯Ό 보νΈν©λλ€.
2. μνΈλ‘νΌμ μ€μμ±
μ§κ°μ 보μμ κ°μΈ ν€λ₯Ό μμ±νλ λ° μ¬μ©λλ 무μμμ± (μνΈλ‘νΌ)μμ μμλ©λλ€. os.urandomμ λλΆλΆμ μ΅μ μ΄μ 체μ μμ μ’μ μμ€μ΄μ§λ§, κ³ κ°μΉ μ ν리μΌμ΄μ
μ κ²½μ° κ°λ°μλ μμΈ‘ λΆκ°λ₯μ±μ 보μ₯νκΈ° μν΄ μ¬λ¬ μμ€μμ μνΈλ‘νΌλ₯Ό μμ§νλ κ²½μ°κ° λ§μ΅λλ€.
3. λλͺ¨λ 문ꡬ (μλ 문ꡬ) - μ°μ νμ€
κΈ΄ 16μ§μ κ°μΈ ν€λ₯Ό μλμΌλ‘ λ°±μ νλ κ²μ λ²κ±°λ‘κ³ μ€λ₯κ° λ°μνκΈ° μ½μ΅λλ€. μ κ³λ κ³μΈ΅μ κ²°μ λ‘ μ (HD) μ§κ° (BIP-32μ μ μλ¨)κ³Ό λλͺ¨λ 문ꡬ (BIP-39)λ‘ μ΄ λ¬Έμ λ₯Ό ν΄κ²°νμ΅λλ€. λλͺ¨λ 문ꡬλ λ§μ€ν° κ°μΈ ν€μ λͺ¨λ νμ ν€λ₯Ό κ²°μ λ‘ μ μΌλ‘ μ¬μμ±νλ λ° μ¬μ©ν μ μλ 12-24κ°μ μΌλ° λ¨μ΄ μνμ€μ λλ€. μ΄λ μ§κ° λ°±μ λ° λ³΅κ΅¬λ₯Ό ν¨μ¬ λ μ¬μ©μ μΉνμ μΌλ‘ λ§λλλ€.
4. μ΄κ²μ κ΅μ‘μ© λꡬμ΄λ©°, νλ‘λμ μ§κ°μ΄ μλλλ€
μ΄ κ΅¬νμ λ¨μνλ λͺ¨λΈμμ λ€μ κ°μ‘°νλ κ²μ΄ μ€μν©λλ€. μ€μ μ§κ°μ μ¬λ¬ μ£Όμλ₯Ό κ΄λ¦¬νκ³ , μμ‘μ μ»κ³ νΈλμμ μ ꡬμ±νκΈ° μν΄ λΈλ‘μ²΄μΈ λ Έλμ μνΈ μμ©νλ©°, μμλ£λ₯Ό κ³μ°νκ³ , μλͺ λ νΈλμμ μ λ€νΈμν¬μ λΈλ‘λμΊμ€νΈν΄μΌ ν©λλ€. λν 보μ μ¬μ©μ μΈν°νμ΄μ€μ κ°λ ₯ν μ€λ₯ μ²λ¦¬κ° νμν©λλ€.
5. λ€νΈμν¬ μνΈ μμ©
μ°λ¦¬μ μ§κ°μ ν€λ₯Ό μμ±νκ³ λ©μμ§μ μλͺ
ν μ μμ§λ§, λΈλ‘μ²΄μΈ λ€νΈμν¬μ ν΅μ ν μλ μμ΅λλ€. μμ ν μ ν리μΌμ΄μ
μ ꡬμΆνλ €λ©΄ RPC (μ격 νλ‘μμ νΈμΆ)λ₯Ό ν΅ν΄ λΈλ‘μ²΄μΈ λ
Έλμ μ°κ²°ν μ μλ λΌμ΄λΈλ¬λ¦¬λ₯Ό ν΅ν©ν΄μΌ ν©λλ€. μ΄λ리μμ κ²½μ° web3.pyκ° νμ€ λΌμ΄λΈλ¬λ¦¬μ
λλ€. λΉνΈμ½μΈμ κ²½μ° python-bitcoinlibμ κ°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©ν μ μμ΅λλ€.
κ²°λ‘ λ° λ€μ λ¨κ³
μΆνν©λλ€! Pythonμ μ¬μ©νμ¬ μνΈνν μ§κ°μ μνΈν ν΅μ¬μ μ±κ³΅μ μΌλ‘ ꡬμΆνμ΅λλ€. μ°λ¦¬λ 곡κ°/κ°μΈ ν€ μνΈνμ κ·Όλ³Έ μ΄λ‘ λΆν° λΉνΈμ½μΈ λ° μ΄λ리μ λ€νΈμν¬ λͺ¨λμ μ ν¨ν μ£Όμλ₯Ό μμ±νλ μ€μ ꡬνμ μ΄λ₯΄κΈ°κΉμ§ μ¬μ μ κ±°μ³€μ΅λλ€.
μ΄ νλ‘μ νΈλ λΈλ‘μ²΄μΈ κΈ°μ μ λν λ κΉμ νꡬλ₯Ό μν κ°λ ₯ν κΈ°λ°μ μ 곡ν©λλ€. μ§κ°μ΄ λ³Έμ§μ μΌλ‘ κ²μ¦λ μνΈν μ리λ₯Ό κΈ°λ°μΌλ‘ ꡬμΆλ μ κ΅ν ν€ κ΄λ¦¬ μμ€ν μμ μ§μ νμΈνμ΅λλ€.
μ¬κΈ°μλΆν° μ΄λλ‘ κ°κΉμ? λ€μ λ¨κ³λ‘ λ€μ κ³Όμ λ₯Ό κ³ λ €ν΄ λ³΄μΈμ:
- HD μ§κ° ꡬν: BIP-32, BIP-39, BIP-44 νμ€μ νμνμ¬ λ¨μΌ λλͺ¨λ μλ 문ꡬμμ μλ°±λ§ κ°μ μ£Όμλ₯Ό κ΄λ¦¬ν μ μλ μ§κ°μ μμ±ν©λλ€.
- λ€νΈμν¬ μ°κ²°:
web3.pyλ₯Ό μ¬μ©νμ¬ μ΄λ리μ λ Έλ (Infura λλ Alchemyμ κ°μ)μ μ°κ²°νκ³ , μ£Όμ μμ‘μ νμΈνκ³ , μμ νΈλμμ μ ꡬμ±ν©λλ€. - μ¬μ©μ μΈν°νμ΄μ€ ꡬμΆ: Tkinterμ κ°μ νλ μμν¬λ₯Ό μ¬μ©νκ±°λ Flask/Djangoλ₯Ό μ¬μ©νμ¬ μΉ μΈν°νμ΄μ€λ₯Ό λ§λ€μ΄ μ§κ°μ λ μ¬μ©μ μΉνμ μΌλ‘ λ§λλλ€.
- λ€λ₯Έ λΈλ‘μ²΄μΈ νμ: λ€λ₯Έ λΈλ‘μ²΄μΈ νλ«νΌμ΄ μ£Όμλ₯Ό μμ±νλ λ°©λ²μ μ‘°μ¬νκ³ μ½λλ₯Ό μ‘°μ νμ¬ μ΄λ₯Ό μ§μν©λλ€.
λΈλ‘μ²΄μΈ μΈκ³λ μ€ν μμ€ νμ κ³Ό μ§μμ λν κ°μ¦ μμ ꡬμΆλ©λλ€. μ΄μ κ°μ λꡬλ₯Ό ꡬμΆν¨μΌλ‘μ¨ λΉμ μ λ¨μν μ½λ©μ λ°°μ°λ κ²μ΄ μλλΌ, μλ‘μ΄ λμ§νΈ κ²½μ μ μΈμ΄λ₯Ό λ°°μ°κ³ μμ΅λλ€. κ³μ μ€ννκ³ , κ³μ ꡬμΆνκ³ , λΆμ° κΈ°μ μ κ΄λν μ μ¬λ ₯μ κ³μ νμνμμμ€.